perm filename SERVO.FAI[CMS,LCS]1 blob
sn#404768 filedate 1978-12-20 generic text, type T, neo UTF8
00100 TITLE SERVO
00200 .INSERT ASMBL.FAI[CMS,LCS]
00300
00400 ;Zero page variables.
00500 ;Not shared.
00600
00700 CURVEL: BLOCK 2 ;Commanded velocity.
00800 0
00900 SETPT: BLOCK 3 ;Current setpoint.
01000 0
01100 SETINC: BLOCK 3 ;Interpolating increment for setpoints.
01200 PREDCT: BLOCK 3 ;Result of the predictive term.
01300 LSTINX: BLOCK 3 ;Position at last index pulse.
01400 OLDSP: BLOCK 3 ;Last commanded setpoint, for CMDVEL.
01500 POSERR: BLOCK 3 ;Current position error.
01600 DACSIG: BLOCK 3 ;Scratch.
01700
01800 ;?
01900 CMDBFL ← 4 ;# of commands to buffer.
02000 CMDBFO: BLOCK CMDBFL ;Command FIFO, low byte of data
02100 CMDBF1: BLOCK CMDBFL ;High byte of data.
02200 CMDBF2: BLOCK CMDBFL ;Command code.
02300 CMDPUT: 0 ;FIFO put pointer.
02400 CMDTAK: 0 ;FIFO take pointer.
02500 CMDCTR: 0 ;Count of entries in FIFO.
02600 ;?
02700
02800 BGLOCK: 0 ;Interlock around background pre. cal.
02900 DSPAT: BLOCK 2 ;Dispatch address when cmds are rcvd?
03000 DSPAT2: BLOCK 2 ;Dispatch when commands are executed?
03100 INCTR: 0 ;Count the interpolations.
03200 HSTTMR: 0 ;Count ticks between host commands.
03300
03400 LOGTMP: BLOCK 4 ;Temp for the arithmetic routines.
03500 CVSAV: BLOCK 2 ;Save area for background variables.
03600 VELSAV: BLOCK 2
03700 BGTMP: BLOCK 2
03800
03900 ZAPEND ← .-1 ;Clear all the above in startup.
04000
04100 CURPOS: BLOCK 3 ;Current position, extended to 3 bytes.
04200 TL: 0 ;Scratch for grey to binary.
04300 TH: 0
04400
04500 ;Shared ram.
04600 LOC 200 ;Second half of zero page.
04700
04800 STATUS: 0 ;Flags for the host.
04900 MODE: 0 ;Mode bits from host.
05000
05100 MEMPTR: BLOCK 2 ;Address pointer for diagnostic read.
05200 NINTER: 0 ;# of interpolations between position
05300 ;commands.
05400 INTSCL: 0 ;# of bits to shift setpoint dif for
05500 ;interpolating.
05600 HSTLIM: 0 ;# of clock ticks allowed between host
05700 0 ;commands.
05800 CMDVEL: BLOCK 2 ;Commanded velocity.
05900 MASS: BLOCK 2 ;Inertia term for prediction.
06000 FRICTN: BLOCK 2 ;Viscous damping coefficient.
06100 GRAVTY: BLOCK 4 ;DC offset for gravity.
06200 POSTOL: BLOCK 4 ;Half-width of position tolerance band.
06300 INTTOL: BLOCK 4 ;Half-width of integration band.
00100 START: CLD
00200 LDXI STKSIZ ;Setup stack.
00300 TXS
00400
00500 LDAI 0
00600 LDXI ZAPEND
00700 RLOOP: STAZX 0 ;Reset ram.
00800 DEX
00900 BPL RLOOP
01000 STAZ CURPOS+2
01100
01200 TAY
01300 BEQ RSTDEF ;Jump
01400
01500
01600 DLOOP: INY
01700 LDAY INITBL ;Init ram.
01800 STAZX 0
01900 INY
02000
02100 RSTDEF: LDXZY INITBLBLBL
02200 CPXI 377
02300 BNE DLOOP
02400
02500 JSR POSUPD ;?
02600 JSR SETCTR ;?
02700
02800 CLI ;?
02900
03000 LDAI 4 ;?
03100 CKSTAT: BITZ IOSTAT ;?
03200 BNE CKSTAT
03300
03400 CKNOT: BITZ IOSTAT ;?
03500 BEQ CKNOT
03600
03700 SEI ;?
03800 LDAI 0 ;?
03900 STAZ IOCTRL ;?
04000
04100 JMP START
04200
04300 INITBL: STATUS ↔ 200
04400 NINTER ↔ =32
04500 INTSCL ↔ 5
04600 WHLSIZ ↔ -=24
04700 HSTLIM ↔ =48
04800 DSPAT+1 ↔ IMBLK⊗-10
04900 DSPAT2+1 ↔ DFBLK⊗-10
05000 DAC ↔ 0
05100 377
00100 ;Clock tick interrupt.
00200 TIKINT: PHA ;Save state.
00300 TXA
00400 PHA
00500 TYA
00600 PHA
00700
00800 LDY ENCL ;Read encoder.
00900 LDA ENCH
01000
01100 ;Convert from grey to binary.
01200 STAZ TH
01300 LSRA
01400 EORZ TH
01500 STAZ TH
01600 TAX
01700
01800 TYA
01900 STAZ TL
02000 RORA
02100 EORZ TL
02200 STAZ TL
02300
02400 LSRZ TH
02500 RORA
02600 LSRZ TH
02700 RORA
02800
02900 EORZ TL
03000 STAZ TL
03100 TAY
03200 TXA
03300 EORZ TH
03400 STAZ TH
03500
03600 LSRA
03700 RORZ TL
03800 LSRA
03900 RORZ TL
04000 LSRA
04100 RORZ TL
04200 LSRA
04300 RORZ TL
04400
04500 EORZ TH
04600 STAZ TH
04700 TYA
04800 EORZ TL
04900 EORZ TH
05000 STAZ TL ;?
00100 JSR POSUPD ;?
00200
00300 STAZ CURPOS
00400 STXZ CURPOS+1
00500 STYZ CURPOS+2
00600
00700 DECZ HSTTMR
00800 BPL HOSTOK
00900
01000 LDAI 0
01100 STAZ HSTTMR
01200 STAZ CMDVEL
01300 STAZ CMDVEL+1
01400
01500 HOSTOK: LDAI 4 ;?
01600 BITZ IOCTRL ;?
01700 BNE INTRS
01800 JMP CURSRV
01900
02000 INTRS: CLC
02100 LDAZ SETPT-1
02200 ADCZ SETINC-1
02300 STAZ SETPT-1
02400 LDAZ SETPT
02500 ADCZ SETINC
02600 STAZ SETPT
02700 LDAZ SETPT+1
02800 ADCZ SETINC+1
02900 STAZ SETPT+1
03000 LDAZ SETPT+2
03100 ADCZ SETINC+2
03200 STAZ SETPT+2
03300
03400 DECZ INCTR
03500 BNE GPOSER
03600
03700 LDAI 0
03800 STAZ SETINC-1
03900 STAZ SETINC
04000 STAZ SETINC+1
04100 STAZ SETINC+2
04200
04300 GPOSER: SEC
04400 LDAZ CURPOS
04500 SBCZ SETPT
04600 STAZ POSERR
04700 LDAZ CURPOS+1
04800 SBCZ SETPT+1
04900 STAZ POSERR+1
05000 LDAZ CURPOS+2
05100 SBCZ SETPT+2
05200 STAZ POSERR+2
00100 BITZ MODE ;?If servo is disabled, we're
00200 BPL OOTOL ;automatically out of tolerance
00300
00400 LDAZ POSERR+2;Test the sign of pos error.
00500 BMI NEGPER
00600
00700 LDAZ POSTOL ;Positive Compare with tol.
00800 CMPZ POSERR
00900 LDAZ POSTOL+1
01000 SBCZ POSERR+1
01100 LDAI 0
01200 SBCZ POSERR+2
01300 BCS TOLOK ;In tolerance.
01400 BCC OOTOL ;Jump.
01500
01600 NEGPER: CLC ;Negative. Add the tolerance.
01700 LDAZ POSTOL
01800 ADCZ POSERR
01900 LDAZ POSTOL+1
02000 ADCZ POSERR+1
02100 LDAI 0
02200 ADCZ POSERR+2
02300 BCS TOLOK ;In tolerance.
02400
02500 OOTOL: LDAZ IOCTRL ;Out of tolerance.
02600 ANDI 177 ;Turn off the in tolerance
02700 BNE WCNTRL ;indicator.
02800
02900 TOLOK: LDAZ IOCTRL ;In tolerance. Turn it on.
03000 ORAI 200 ;?
03100 WCNTRL: STAZ IOCTRL ;?
03200
03300 BITZ MODE ;If intergration is disabled,
03400 BVC OOBAND ;turn it off.
03500 LDAZ POSERR+2;Test sign of position error.
03600 BMI ADTOL
03700
03800 LDAZ INTTOL ;Positive. Compare with tol.
03900 CMPZ POSERR
04000 LDAZ INTTOL+1
04100 SBCZ POSERR+1
04200 LDAI 0
04300 SBCZ POSERR+2
04400 BCS INBAND
04500 BCC OOBAND
04600
04700 ADTOL: CLC ;Negative. Add the tolerance.
04800 LDAZ INTTOL
04900 ADCZ POSERR
05000 LDAZ INTTOL+1
05100 ADCZ POSERR+1
05200 LDAI 0
05300 ADCZ POSERR+2
05400 BCS INBAND
05500
05600 OOBAND: LDAZ IOCTRL ;Out of band. Turn off
05700 ORAI 10 ;?integration by setting the
05800 ANDI 357 ;?control bit. LSB servo off.
05900 BNE WCTRL2
00100 INBAND: LDAI LSBENB ;In band. Is LSB servo enabled
00200 BITZ MODE ;?
00300 BEQ RCNTRL
00400
00500 LDAZ POSERR ;Yes. Is the error exactly 0?
00600 ORAZ POSERR+1
00700 ORAZ POSERR+2
00800 BNE RCNTRL
00900
01000 LDAZ IOCTRL ;?It is. Integration off, LSB
01100 ORAI 30 ;?servo on.
01200 BNE WCTRL2 ;Jump.
01300
01400 RCNTRL: LDAZ IOCTRL ;?LSB disabled or error
01500 ANDI 347 ;?not zero. LSB servo off,
01600 ;?integration on.
01700
01800 WCTRL2: STAZ IOCTRL ;?
00100 LDAZ LOGTMP ;Since the arithmetic routines
00200 LDYZ LOGTMP+1;aren't re-entrant, we need to
00300 STAZ LOGTMP+2;save their state here.
00400 STYZ LOGTMP+3
00500
00600 LDYZ CURVEL ;Get the velocity,
00700 LDAZ CURVEL+1
00800 JSR LOG
00900 LDXI FRICTN ;mult. by the friction
01000 JSR MUL ;coefficient,
01100 JSR EXP
01200 TAX
01300 TYA
01400 CLC ;add the position error...
01500 ADCZ POSERR
01600 STAZ DACSIG
01700 TXA
01800 ADCZ POSERR+1
01900 STAZ DACSIG+1
02000 LDYI 0
02100 TXA ;(sign-extend the velocity)
02200 BPL NODEY
02300 DEY
02400
02500 NODEC: TYA
02600 ADCZ POSERR+2
02700 STAZ DACSIG+2
02800
02900 CLC ;...the velocity predictive term...
03000 LDAZ DACSIG
03100 ADCZ PREDCT
03200 STAZ DACSIG
03300 LDAZ DACSIG+1
03400 ADCZ PREDCT+1
03500 STAZ DACSIG+1
03600 LDAZ DACSIG+2
03700 ADCZ PREDCT+2
03800 STAZ DACSIG+2
03900
04000 CLC ;...and the gracity offset.
04100 LDAZ DACSIG
04200 ADCZ GRAVTY
04300 TAY
04400 LDAZ DACSIG+1
04500 ADCZ GRAVTY+1
04600 TAX
04700 LDAZ DACSIG+2
04800 ADCZ GRAVTY+2
04900
05000 JSR PUTDAC ;Put result out to the DAC.
05100
05200 LDYZ LOGTMP+3;Restore the arithmetic
05300 LDAZ LOGTMP+2;routines' state.
05400 STYZ LOGTMP+1
05500 STAZ LOGTMP
05600
05700 CMDSP:
00100 CMDEND: LDAI 4 ;Done with commands.
00200 BITZ IOCTRL ;Are we servoing?
00300 BEQ INTXIT
00400 BITZ BGLOCK ;Yes. Is the background
00500 BMI INTXIT ;predictor still running?
00600
00700 DECZ BGLOCK ;No. Start it up.
00800 JMP BGSRV
00900
01000 BGDON: INCZ BGLOCK ;Unlock?
01100
01200 INTXIT: PLA ;Restore state and dismiss interrupt.
01300 TAY
01400 PLA
01500 TAX
01600 PLA
01700 RTI
01800
01900 ;Background velocity prediction.
02000 BGSRV: LDAZ CURVEL ;Copy the variables used to
02100 STAZ VELSAV ;avoid interference from
02200 LDAZ CURVEL+1;interrupts while this routine
02300 STAZ VELSAV+1;is running.
02400 LDAZ CMDVEL
02500 STAZ CVSAV
02600 LDAZ CMDVEL+1
02700 STAZ CVSAV+1
02800 LDYZ POSERR
02900 LDAZ POSERR+1
03000 LDXZ POSERR+2
03100
03200 CLI ;Enable interrupts?
03300
03400 PHA
03500 ASLA ;Is magnitude of position error
03600 TXA ;< 2↑15?
03700 ADCI 0
03800 BEQ FLOERR
03900
04000 PLA ;No. Set the predictive term to zero.
04100 LDAI 0
04200 TAX
04300 TAY
04400 JMP NTRLOC
04500
04600 FLOERR: PLA ;Yes. Float the position error.
04700 JSR LOG
04800 JSR INV ;TMP = 1 / POSERR
04900 STYZ BGTMP
05000 STAZ BGTMP+1
05100 CLC
05200 LDAZ CVSAV ;Commanded velocity + current
05300 ADCZ VELSAV ;velocity...
05400 TAY
05500 LDAZ CVSAV+1
05600 ADCZ VELSAV+1
00100 JSR LOG ;...float...
00200 LDXI BGTMP
00300 JSR MUL ;...* TMP...
00400 STYZ BGTMP ;...stored at TMP.
00500 STAZ BGTMP+1
00600 SEC
00700 LDAZ CVSAV ;Commanded velocity - current
00800 SBCZ VELSAV ;velocity...
00900 TAY
01000 LDAZ CVSAV+1
01100 SBCZ VELSAV+1
01200 JSR LOG ;...same thing.
01300 LDXI BGTMP
01400 JSR MUL
01500 STYZ BGTMP
01600 STAZ BGTMP+1
01700
01800 SEI ;?Interlock...
01900
02000 LDYZ ;...get the mass...
02100 LDAZ MASS+1
02200
02300 CLI ;?clear the lock.
02400
02500 JSR MUL ;Scale the predictor.
02600 JSR EXP ;Back to integer form.
02700 LDXI 0
02800 CMPI 0
02900 BPL NTRLOC ;Extend sign to 3 bytes.
03000 DEX
03100
03200 NTRLOC: SEI ;End of background. Interlock.
03300
03400 STYZ PREDCT
03500 STAZ PREDCT+1;Store the result for the servo
03600 STXZ PREDCT+2;to use.
03700 JMP BGDON
00100 ;Subroutines?
00200 ;Enter with position in A (low), X (middle), Y (high).
00300 ;Sets current position to that value, puts the setpoint
00400 ;to the same, clears the setpoint interpolating
00500 ;increment, and goes into stop mode.
00600 SETCTR: PHA
00700 SEC ;Get low byte of position change,
00800 SBCZ CURPOS
00900 CLC
01000 ADCZ POSOFF ;add it to the counter offset?
01100 STAZ POSOFF
01200 PLA
01300 STAZ CURPOS ;Set the current position.
01400 STXZ CURPOS+1
01500 STYZ CURPOS+2
01600
01700 ;Second entry - freeze to the position in A, X, Y as
01800 ;above without changing the current position.
01900 FREEZE: STAZ SETPT ;Set the position command.
02000 STXZ SETPT+1
02100 STYZ SETPT+2
02200 STAZ OLDSP
02300 STXZ OLDSP+1
02400 STYZ OLDSP+2
02500
02600 LDAI 75 ;I/O control bits for servo
02700 STAZ IOCTRL ;?enable on, all others off.
02800
02900 LDAI 0
03000 STAZ SETPT-1 ;Clear the setpoint extension
03100 STAZ SETINC-1;and the interpolator
03200 STAZ SETINC
03300 STAZ SETINC+1
03400 STAZ SETINC+2
03500 STAZ CMDVEL ;and the commanded velocity.
03600 STAZ CMDVEL+1
03700
03800 LDAZ SETPT ;Return the regs. unchanged.
03900 RTS
04000 ;Enter with low counter value in Y.
04100 ;Returns updated position in A (low), X (middle),
04200 ;Y (high). Also sets CURVEL to the 16-bit signed
04300 ;velocity.
04400 POSUPD: TYA ;?Add the counter offset to get
04500 CLC ;?the low byte of the position.
04600 ADCZ POSOFF ;?
04700 STAZ DACSIG ;Save that value.
04800 LDXI 0
04900 SEC
05000 SBCZ CURPOS ;Subtract the old position
05100 STAZ CURVEL ;yielding the velocity.
05200 BPL SVVEL
05300 DEX ;Extend sign to 16 bits.
05400 SVVEL: STXZ CURVEL+1
05500 LDXZ CURPOS+1 ;Set up for updating bytes
05600 LDYZ CURPOS+2 ;2 and 3.
05700 LDAZ DACSIG ;Did bit 7 of position change?
05800 EORZ CURPOS
05900 BPL GETDAC ;If not, we're through.
06000 LDAZ CURVEL ;It did. Which way did we move
06100 BMI DOWN
06200 LDAZ DACSIG ;Upward.
06300 BMI GETDAC ;If bit 7 is on, we're done.
06400 INX ;Off. Increment middle byte
06500 BNE GETDAC
06600 INY ;and high byte if necessary.
06700 JMP GETDAC
06800
06900 DOWN: LDAZ DACSIG ;Downward.
07000 BPL GETDAC ;If bit 7 is off, we're done.
07100 CPXI 0 ;On.
07200 BNE DX
07300 INY ;Increment high byte if necessary
07400 DX: DEX ;and middle byte.
07500
07600 GETDAC: LDAZ DACSIG
07700 RTS
00100 ;DAC output subroutine. Not sub?
00200 ;Enter with 3 byte value in Y (low), X (middle),
00300 ;A (high). Clobbers all registers, but the 8 bits the
00400 ;DAC got are returned in?
00500 PUTDAC: BMI NEGDAG ;Assuming the last I. loaded A.
00600 CPYI 200 ;Positive. Compare with 2↑7.
00700 BCS TOOHI
00800 CPXI 1
00900 SBCI 0
01000 BCC INRNGE
01100
01200 TOOHI: LDYI 177 ;Too high. Saturate positive.
01300 BNE INRNGE ;Jump.
01400
01500 NEGDAC: CPYI 200 ;Negative. Compare with -2↑7.
01600 BCC TOOLOW
01700
01800 CPXI 377
01900 SBCI 377
02000 BCS INRNGE
02100
02200 TOOLOW: LDYI 200 ;Too low. Saturate to -2↑7.
02300
02400 INRNGE: STY DAC ;Output 8 bits to the DAC.
02500 RTS
02600
02700 DOUBLE: PHA ;Doubles the position in (Y,X,A) if
02800 LDAI DBLMOD ;the double mode bit is set.
02900 BITZ MODE
03000 BEQ NOTDBL
03100 PLA
03200 ASLA
03300 PHA
03400 TXA
03500 ROLA
03600 TAX
03700 TYA
03800 ROLA
03900 TAY
04000 NOTDBL: PLA
04100 RTS
04200
04300 HALVE: PHA ;Halve the position argument in (Y,X,A)
04400 LDAI DBLMOD ;if the double mode bit is set.
04500 BITZ MODE
04600 BEQ NOTDBL
04700 TYA
04800 CMPI 200
04900 RORA
05000 TAY
05100 TXA
05200 RORA
05300 TAX
05400 PLA
05500 RORA
05600 RTS
00100 ENBTST: PHA ;Test for servo enabled and not locked
00200 LDAZ MODE ;on the wheel index.
00300 ANDI 202
00400 CMPI 200
00500 BNE NOTENB
00600 PLA ;OK. Return.
00700
00800 NOTENB: PLA ;No. Wipe the return address and
00900 PLA ;end this command.
01000 PLA
01100 JMP CMDEND
00100 ;Enter with high byte in A, low in Y.
00200 ;Returns A = characteristic and sign, Y = mantissa.
00300 ;Clobbers X, LOGTMP, LOGTMP+1.
00400 LOG: STYZ LOGTMP ;Save the inputs.
00500 STAZ LOGTMP+1
00600
00700 LDXI 20+100 ;?Init characteristic to 15.
00800 CMPI 0 ;Test sign of input.
00900 BPL POSIN
01000 SEC ;Negative. 2's complement it.
01100 LDAI 0
01200 SBCZ LOGTMP
01300 STAZ LOGTMP
01400 LDAI 0
01500 SBCZ LOGTMP+1
01600 POSIN: BNE NORML ;Is high byte zero?
01700 LDAZ LOGTMP ;Yes. Low byte?
01800 BEQ RTRN ;If so, return zero.
01900 LDYI 0 ;Low nonzero. Shift left one
02000 STYZ LOGTMP ;byte,
02100 LDXI 10+100 ;?change characteristic to 7.
02200 NORML: DEX ;Normalize the number, counting the
02300 ASLZ LOGTMP ;characteristic down. When the
02400 ROLA ;first "1" shifts out, we've subtracted
02500 BCC NORML ;1 from the normalized number
02600 ASLZ LOGTMP ;(This rounds the result)
02700 ADCI =11 ;and are left with the fraction
02800 TAY ;Adding 11 to that is equivalent to
02900 TXA ;adding 0.043.
03000 ADCI 0 ;Propagate the carry into the
03100 ;characteristic.
03200 ASLA ;Insert the sign bit from the saved
03300 ASLZ LOGTMP+1;input.
03400 RORA
03500 RTRN: RTS ;Done.
03600
03700 ;Enter with sign and characteristic in A, mantissa in Y
03800 ;Returns 16-bit integer, low byte in Y, high in A.
03900 ;Clobbers X, LOGTMP, LOGTMP+1.
04000 EXP: STAZ LOGTMP+1;Save sign of input.
04100 ANDI 177 ;Mask it off.
04200 BEQ ZEROIN ;Zero characteristic returns
04300 TAX ;zero.
04400 TYA ;Get the mantissa...
04500 SEC
04600 SBCI =11 ;...subtract 0.043...
04700 STAZ LOGTMP ;(save this value)
04800 TXA ;...propagate the carry and get rid
04900 SBCI 100 ;of the XS-64 offset.
05000 BMI NEGIN ;If negative (value < 1.0)
05100 ;return zero.
05200 CMPI =15 ;Test for overflow (value>=2↑15
05300 BCS SATUR
05400 TAX ;...no. Number is in range.
05500 ADCI -10 ;?Is characteristic below 8?
05600 BMI BLOATE
05700 TAX ;No. Reduce if by 8,
05800 JSR UNNORM ;unnormalize.
05900 BMI GETTMP ;Jump.
00100 BLOATE: JSR UNNORM ;Yes. Unnormalize, then
00200 ASLZ LOGTMP ;(round result)
00300 ADCI 0
00400 STAZ LOGTMP ;use result as low byte and
00500 LDAI 0 ;set high byte to zero.
00600
00700 GETTMP: LDYZ LOGTMP
00800 GTMP1: LDXZ LOGTMP+1;Test sign of input...
00900 BPL POSIGN
01000 STAZ LOGTMP+1;...negative. 2's complement
01100 LDAI 0 ;the result.
01200 SEC
01300 SBCZ LOGTMP
01400 TAY
01500 LDAI 0
01600 SBCZ LOGTMP+1
01700 POSIGN: RTS
01800
01900 NEGIN: LDAI 0 ;Set the result to zero if the
02000 ZEROIN: TAY ;input is negative.
02100 RTS
02200
02300 SATUR: LDYI OFF ;Saturate result to 2↑15 - 1 if
02400 STYZ LOGTMP ;input was 15 or more.
02500 LDAI 177
02600 BNE GTMP1 ;Jump.
02700
02800 UNNORM: LDAI 1 ;Unnormalize subroutine. Add 1
02900 BNE DECRX ;to the fraction.
03000
03100 SCALE: ASLZ LOGTMP ;Scale the fraction left by the
03200 ROLA ;amount of the characteristic.
03300 DECRX: DEX
03400 BPL SCALE
03500 RTS
03600
03700 ;Enter with characteristic of multiplier in A,
03800 ;mantissa in Y, X pointing to a pair of base page
03900 ;locations containing the multiplicand (mantissa in the
04000 ;low byte).
04100 ;Returns the product in A and Y, same form as the
04200 ;multiplier. Leaves X unchanged. Clobbers LOGTMP and
04300 ;LOGTMP+1.
04400 MUL: PHA
04500 EORZX 1 ;Compute sign of result,
04600 STAZ LOGTMP+1 ;save it away.
04700 PLA
04800 ANDI 177 ;Mask off multiplier sign.
04900 BEQ ZEROIN ;If zero, return zero.
05000 STAZ LOGTMP
05100 TYA ;Add the two logarithms.
05200 CLC
05300 ADCZX 0
05400 TAY
05500 LDAZX 1
05600 ANDI 177 ;If multiplicand is zero,
05700 BEQ ZEROIN ;return a zero.
05800 ADCZ LOGTMP
05900 SEC
06000 SBCI 100 ;Correct the XS-64 offset.
00100 BPL INSIGN ;Result in range?
00200 ANDI 100 ;No. If underflow,
00300 BNE NEGIN ;return zero.
00400 LDAI 177 ;Overflow. Saturate to
00500 LDYI 377 ;highest magnitude.
00600
00700 INSIGN: ASLA ;Insert the sign of the result.
00800 ASLZ LOGTMP+1
00900 RORA
01000 RTS
01100
01200 ;Inverse function: 2's complement the magnitude part
01300 ;of a 15-bit logarithm.
01400 ;Enter with characteristic in A, mantissa in Y.
01500 ;Returns inverse in the same form. X unchanged.
01600 ;Clobbers LOGTMP and LOGTMP+1.
01700 INV: STYZ LOGTMP ;Pretty straightforward...
01800 STAZ LOGTMP+1
01900 SEC
02000 LDAI 0 ;Complement the number by
02100 SBCZ LOGTMP ;subtracting it from zero.
02200 TAY
02300 LDAI 0
02400 SBCZ LOGTMP+1
02500 JMP INSIGN ;Insert the original sign.
02600 END